#include "StdAfx.h"
#include ".\lsysbranchrule.h"
#include "vector.h"
#include "MutationHelpers.h"
#include "CrossoverHelpers.h"

#include "afxwin.h"

#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>

LsysBranchRule::LsysBranchRule(void)
{
	m_lfScale = 100.0;
	m_lfBaseWidth = 0.25;
	m_lfWidthRatio = 0.5;
	m_nSlices = 10; 
	m_nStacks=1;
}

LsysBranchRule::~LsysBranchRule(void)
{
}

void LsysBranchRule::BranchRotStruct::Creep(double lfCreepWidth)
{
	m_lfPhi = CreepVal(m_lfPhi, lfCreepWidth, 90.0 /*GenericMath::pi*/);
	m_lfPhiDistroWidth = CreepVal(m_lfPhiDistroWidth, lfCreepWidth, 90.0 /*GenericMath::piOver2*/);

	m_lfTheta = CreepVal(m_lfTheta, lfCreepWidth, 360.0 /*GenericMath::twoPi*/);

	m_lfThetaDistroWidth = CreepVal(m_lfThetaDistroWidth, lfCreepWidth, 180.0);
}

void LsysBranchRule::BranchRotStruct::Crossover(
	LsysBranchRule::BranchRotStruct branch1, 
	LsysBranchRule::BranchRotStruct branch2, double lfProb1)
{
	m_lfPhi = ProbSelect(lfProb1, 
		branch1.m_lfPhi, 
		branch2.m_lfPhi);

	m_lfPhiDistroWidth = ProbSelect(lfProb1, 
		branch1.m_lfPhiDistroWidth, 
		branch2.m_lfPhiDistroWidth);

	m_lfTheta = ProbSelect(lfProb1, 
		branch1.m_lfTheta, 
		branch2.m_lfTheta);
	
	m_lfThetaDistroWidth = ProbSelect(lfProb1, 
		branch1.m_lfThetaDistroWidth, 
		branch2.m_lfThetaDistroWidth);
}

void LsysBranchRule::BranchRotStruct::SetRandomly()
{
	m_lfPhi = GenericMath::RandRange(0.0, 90.0);
	m_lfPhiDistroWidth = GenericMath::RandRange(0.0, 45.0);

	m_lfTheta = GenericMath::RandRange(0.0, 360.0);
	m_lfThetaDistroWidth = GenericMath::RandRange(0.0, 90.0);
}

void LsysBranchRule::BranchRotStruct::PrettyRandomize()
{
	m_lfPhi = GenericMath::RandRange(0.0, 45.0);
	m_lfPhiDistroWidth = GenericMath::RandRange(0.0, 15.0);

	m_lfTheta = GenericMath::RandRange(0.0, 360.0);
	m_lfThetaDistroWidth = GenericMath::RandRange(0.0, 90.0);
}

void LsysBranchRule::BranchDescr::Creep(double lfCreepWidth)
{
	m_lfBranchScale = CreepVal(m_lfBranchScale, lfCreepWidth, 1.0);
	m_lfDistAlongToBranch = CreepVal(m_lfDistAlongToBranch, lfCreepWidth, 1.0);
	m_lfProbability = CreepVal(m_lfProbability, lfCreepWidth, 1.0);

	m_rotParams.Creep(lfCreepWidth);
}

void LsysBranchRule::BranchDescr::SetRandomly()
{
	m_lfBranchScale = 0.5+GenericMath::PoorMansGaussian();
	m_lfBranchScale = Clamp(m_lfBranchScale, 1.0);
	
	m_lfDistAlongToBranch = 0.75+GenericMath::PoorMansGaussian();
	m_lfDistAlongToBranch = Clamp(m_lfDistAlongToBranch, 1.0);
	

	m_lfProbability = 0.75+GenericMath::PoorMansGaussian();
	m_lfProbability = Clamp(m_lfProbability, 1.0);
	m_rotParams.SetRandomly();
}

void LsysBranchRule::BranchDescr::PrettyRandomize()
{

	m_lfDistAlongToBranch = 0.75+0.2*GenericMath::PoorMansGaussian();
	m_lfDistAlongToBranch = Clamp(m_lfDistAlongToBranch, 1.0);

	m_lfBranchScale = 0.5+0.5*(1.0-m_lfDistAlongToBranch);

	

	m_lfBranchScale += Clamp((0.05*GenericMath::PoorMansGaussian()+0.05), 0.1)-0.05;

	m_lfBranchScale = Clamp(m_lfBranchScale, 1.0);

	m_lfProbability = 0.8+0.1*GenericMath::PoorMansGaussian();
	m_lfProbability = Clamp(m_lfProbability, 1.0);
	m_rotParams.PrettyRandomize();
}

void LsysBranchRule::BranchDescr::Crossover(
	LsysBranchRule::BranchDescr branch1, 
	LsysBranchRule::BranchDescr branch2, double lfProb1)
{
	m_lfBranchScale = ProbSelect(lfProb1, 
		branch1.m_lfBranchScale, 
		branch2.m_lfBranchScale);

	m_lfDistAlongToBranch = ProbSelect(lfProb1, 
		branch1.m_lfDistAlongToBranch, 
		branch2.m_lfDistAlongToBranch);

	m_lfProbability = ProbSelect(lfProb1, 
		branch1.m_lfProbability, 
		branch2.m_lfProbability);

	m_rotParams.Crossover(branch1.m_rotParams, branch2.m_rotParams, lfProb1);
}

void LsysBranchRule::Creep(double lfCreepWidth)
{
	m_lfWidthRatio = CreepVal(m_lfWidthRatio, 0.375*lfCreepWidth, 0.75);
	m_lfBaseWidth = CreepVal(m_lfBaseWidth, 0.25*lfCreepWidth, 0.5);
	for(int i = 0; i < MAX_BRANCHES_PER_RULE; ++i)
	{
		m_BranchDescr[i].Creep(lfCreepWidth);
	}
}

void LsysBranchRule::Crossover(LsysBranchRule branch1, LsysBranchRule branch2, double lfProb1)
{
	m_lfWidthRatio = ProbSelect(lfProb1, branch1.m_lfWidthRatio, branch2.m_lfWidthRatio);
	m_lfBaseWidth = ProbSelect(lfProb1, branch1.m_lfBaseWidth, branch2.m_lfBaseWidth);
	for(int i = 0; i < MAX_BRANCHES_PER_RULE; ++i)
	{
		m_BranchDescr[i].Crossover(
			branch1.m_BranchDescr[i],
			branch2.m_BranchDescr[i],
			lfProb1);
	}
}

void LsysBranchRule::DrawCone()
{
	
	static GLUquadricObj * pQObj = NULL;
	if(!pQObj)
	{
		pQObj = gluNewQuadric();
	}


	gluCylinder(pQObj, m_lfBaseWidth, m_lfBaseWidth*m_lfWidthRatio, 1.0, 
		m_nSlices, m_nStacks);

}

void LsysBranchRule::DoTransform(int nWhichChild, int nArrPos, ParamVector * arrParams)
{


	double lfNewTheta = m_BranchDescr[nWhichChild].m_rotParams.m_lfTheta +
		GenericMath::PoorMansGaussian(arrParams[nArrPos][1])*
		m_BranchDescr[nWhichChild].m_rotParams.m_lfThetaDistroWidth;

	double lfNewPhi = m_BranchDescr[nWhichChild].m_rotParams.m_lfPhi +
		GenericMath::PoorMansGaussian(arrParams[nArrPos][2])*
		m_BranchDescr[nWhichChild].m_rotParams.m_lfPhiDistroWidth;

	glTranslated(0.0, 0.0, m_BranchDescr[nWhichChild].m_lfDistAlongToBranch);
	
	// double lfScale = m_BranchDescr[nWhichChild].m_lfBranchScale;
	// double lfScale = 0.5+0.5*(1.0-m_BranchDescr[nWhichChild].m_lfDistAlongToBranch);
	double lfScale = 
		(m_lfWidthRatio + 
		(1.0-m_lfWidthRatio)*(1.0-m_BranchDescr[nWhichChild].m_lfDistAlongToBranch));
	glScaled(lfScale, lfScale, lfScale);

	glRotated(lfNewTheta, 0.0, 0.0, 1.0);

	glRotated(lfNewPhi, 1.0, 0.0, 0.0);
	// from BranchRotStruct
	//double m_lfTheta;
	//double m_lfPhi;

	//double m_lfPhiDistroWidth;
	//double m_lfThetaDistroWidth;

	// from BranchDescr
	//double m_lfBranchScale; // normalized, goes between 0 and 1
	//double m_lfDistAlongToBranch; // normalized, goes between 0 and 1
}

void LsysBranchRule::InternalRecursiveDraw(int nLevelsLeft, int nChildIdx, int nArrPos, ParamVector * arrParams)
{
	if(arrParams[nArrPos][0] > m_BranchDescr[nChildIdx].m_lfProbability)
	{
		return;
	}

	glPushMatrix();

	// draw the main branch

	//if(nLevelsLeft < 1)
	//{
	//	glColor3d(0.1, 0.7, 0.1);
	//}

	DoTransform(nChildIdx, nArrPos, arrParams);
	DrawCone();

	if(nLevelsLeft < 1)
	{
		// glColor3d(0.75, 0.5, 0.25);
		glPopMatrix();
		return;
	}

	int nPosNext = nArrPos*MAX_BRANCHES_PER_RULE;
	for(int i = 0; i < MAX_BRANCHES_PER_RULE; ++i)
	{
		
		// do this if the branch is not broken
		InternalRecursiveDraw(nLevelsLeft-1, i, nPosNext, arrParams);
		++nPosNext;
	}

	glPopMatrix();
}

void LsysBranchRule::Draw(int nLevels, double arrLfProbabilities[][TOT_PARAMS_PER_BRANCH])
{
	// draw the main branch

	glColor3d(0.75, 0.5, 0.25);
	glEnable(GL_NORMALIZE);
	glPushMatrix();

	glScaled(m_lfScale, m_lfScale, m_lfScale);

	DrawCone();

	for(int i = 0; i < MAX_BRANCHES_PER_RULE; ++i)
	{
		InternalRecursiveDraw(nLevels-1, i, i+1, arrLfProbabilities);
	}


	glPopMatrix();
}


void LsysBranchRule::PrettyRandomize()
{
	m_lfWidthRatio = 0.25 + GenericMath::RandRange(0.0, 0.5);
	m_lfBaseWidth = 0.125 + GenericMath::RandRange(0.0, 0.25);

	for(int i = 0; i < MAX_BRANCHES_PER_RULE; ++i)
	{
		m_BranchDescr[i].PrettyRandomize();
	}
}

void LsysBranchRule::SetRandomly()
{
	m_lfWidthRatio = 0.25 + GenericMath::RandRange(0.0, 0.5);
	m_lfBaseWidth = 0.125 + GenericMath::RandRange(0.0, 0.25);
	
	for(int i = 0; i < MAX_BRANCHES_PER_RULE; ++i)
	{
		m_BranchDescr[i].SetRandomly();
	}
}

int LsysBranchRule::GetProbArrNumEnts(int nLevels) const
{
	if(nLevels < 1)
	{
		return 1;
	}

	return 1+MAX_BRANCHES_PER_RULE*GetProbArrNumEnts(nLevels-1);
}


void LsysBranchRule::RandomlySetParamArr(int nLevels, 
										 double arrLfProbabilities[][TOT_PARAMS_PER_BRANCH]) const
{
	int nEntries = GetProbArrNumEnts(nLevels);

	
	for(int i = 0; i < nEntries; ++i)
	{
		for(int j = 0; j < TOT_PARAMS_PER_BRANCH; ++j)
		{
			arrLfProbabilities[i][j] = GenericMath::RandRange(0.0, 1.0);
		}
	}
}